/*
 * Copyright (c) 2010 Philip Foulkes <philip.foulkes@gmail.com>
 *
 * This file is free software and is made available under the 
 * terms of the GNU General Public License, version 2, or at your
 * option, any later version
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#ifndef _MRP_H_
#define _MRP_H_

#include "mrp_iterator.h"

/**
*   MRP EtherType values
*/
#define MRP_ETHERTYPE_MMRP 0x88F6
#define MRP_ETHERTYPE_MVRP 0x88F5
#define MRP_ETHERTYPE_MSRP 0x22EA

/**
*   MRP application addresses
*/
extern const u8 mrp_application_address_mmrp [6];
extern const u8 mrp_application_address_mvrp [6];
extern const u8 mrp_application_address_msrp [6];

struct mrp;

typedef int (*message_processing_thread_fucntion) (void * data);

/* 
 * Returns an integral value indicating the relationship between the two attributes
 * A zero value indicates that the attribute values are the same
 * A value greater than zero indicates that the first attribute has a greater value than the second attribute. A value less than zero indicates the opposite
 */
typedef int (*mrp_attribute_value_compare)(void *, void *);

typedef void (*mrp_attribute_value_destroy) (void **);

/*
 * The MAD component executes the MRP protocol (10.6, 10.7), generating MRP messages for transmission
 * and processing messages received from other Participants, and uses the following two primitives to notify its
 * application component of a change in Attribute registration:
 */
typedef int (*mrp_mad_join_indication)  (struct mrp * mrp, int mrp_attribute_type, void * attribute_value, int four_packed_type, int new);
typedef int (*mrp_mad_leave_indication) (struct mrp * mrp, int mrp_attribute_type, void * attribute_value, int four_packed_type);

/*
 * Return a pointer to a function used to compare the attribute identified by attribute_type
 */
typedef mrp_attribute_value_compare (*mrp_get_attribute_value_compare) (int attribute_type);

/*
 * Return the length of the attribute referred to by attribute_type
 */
typedef int (*mrp_get_attribute_length) (int attribute_type);

/*
 * Return 0 to indicate that the attribute referred to by attribute_type does not need the four packed events field. Return not zero otherwise
 */
typedef int (*mrp_does_need_four_packed_events) (int attribute_type);

typedef int (*mrp_get_four_packet_event_value) (struct mrp * mrp, int attribute_type, void * attribute_value, u8 * four_packed_event_type);

/*
 * Incremement the first_value as defined by the specific MRP application
 */
typedef int (*mrp_increment_first_value) (int attribute_type, void * first_value, int how_much);


/* 
 * MRP applications need to provide and implementation of each of these methods to ensure the correct operation of their protocol
 */
struct mrp_ops
{
	mrp_mad_join_indication  			mrp_mad_join_indication;            /* MAD join indication */
	mrp_mad_leave_indication 			mrp_mad_leave_indication;           /* MAD leave indication */
	mrp_get_attribute_value_compare 	mrp_get_attribute_value_compare;    /* get a function pointer allowing MRP to compare two attribute values */
	mrp_get_attribute_length 			mrp_get_attribute_length;           /* get the length of the attribute */
	mrp_increment_first_value			mrp_increment_first_value;          /* increment the first value */
	mrp_does_need_four_packed_events 	mrp_does_need_four_packed_events;   /* does the application use the four packed events field */
};

/**
*   Represents an MRP Application. All members should be considered opaque. All interaction with MRP should happen through the methods below.
*/
struct mrp
{    
    struct mrp_port * mrp_port;
	struct mrp_ops  * mrp_ops;
	
	int use_attribute_list_length;
	
	struct mrp_leave_all * mrp_leave_all;
	struct mrp_periodic_transmission * mrp_periodic_transmission;
	
	struct list_head attributes;
    
    struct mrp_map * mrp_map;
	
	struct mrp_message_processing_thread * mrp_message_processing_thread;
	
	struct timer_list jointimer;
	struct list_head request_opportunity_list;
	
	int protocol_version;
	
	struct mrp_iterator mrp_iterator;
	struct list_head * mrp_iterator_list_head;
    
    struct list_head inidcation_ops_list;
    
    struct list_head map_list;
};

struct mrp * mrp_create_and_init (const u8 application_address [6], u16 ether_type, const char * port_name, struct mrp_ops * mrp_ops, int protocol_version, int use_attribute_list_length);
int mrp_init   (struct mrp * mrp, const u8 application_address [6], u16 ether_type, const char * port_name, struct mrp_ops * mrp_ops, int protocol_version, int use_attribute_list_length);

void mrp_destroy (struct mrp ** mrp);
void mrp_clean_up (struct mrp * mrp);

/** 
 * Request MAD to make an Attribute declaration
 * mrp_attribute_type specifies the type of the attribute declaration
 * attribute_value specifies the instance of that type
 * the Boolean new parameter indicates an explicit new declaration
 */
int mrp_mad_join_request_notify  (struct mrp * mrp, int mrp_attribute_type, void * attribute_value, int four_packed_type, int new);

/**
 * Request MAD to withdraw an Attribute declaration
 * mrp_attribute_type specifies the type of the attribute declaration
 * attribute_value specifies the instance of that type
 */
int mrp_mad_leave_request_notify (struct mrp * mrp, int mrp_attribute_type, void * attribute_value);

int mrp_leave_request_on_all_attributes_notify (struct mrp * mrp);

/**
 * Enable the Periodic Transmission state machine
 */
int mrp_periodic_enable_notify  (struct mrp * mrp);

/**
 * Disable the Periodic Transmission state machine
 */
int mrp_periodic_disable_notify (struct mrp * mrp);

/**
 * Used to iterate through the attributes
 */
struct mrp_iterator * mrp_get_mrp_attribute_iterator (struct mrp * mrp);

int mrp_call_function_on_message_thread (struct mrp * mrp, message_processing_thread_fucntion message_processing_thread_fucntion, void * data);

int mrp_is_address_an_mrp_application_address (u8 address [6]);
int mrp_is_address_a_vlan_component_reserved_address (u8 address [6]);

#endif
